#include "NativeToJSBridge.h"

#include "utils/DynamicConverter.h"

namespace bridge {
NativeToJSBridge::NativeToJSBridge(std::shared_ptr<Runtime> runtime, std::shared_ptr<ModuleRegistry> registry,
                                   std::shared_ptr<MessageQueue> jsQueue)
    : jsQueue_(jsQueue), jsiExecutor_(std::make_unique<JSIExecutor>(runtime, registry)) {}

void NativeToJSBridge::initializeRuntime() {
  runOnExecutorQueue([](JSIExecutor* executor) mutable { executor->initializeRuntime(); });
}

void NativeToJSBridge::callFunction(const std::string&& module, const std::string&& method, Dynamic&& arguments) {
  runOnExecutorQueue([this, module = std::move(module), method = std::move(method),
                      arguments = std::move(arguments)](JSIExecutor* executor) {
    auto runtime = executor->getRuntime();
    auto val = dynamic::dynamicToValue(*runtime, arguments);
    executor->callNativeModule(module, method, val.getObject(*runtime).asArray(*runtime));
  });
}

void NativeToJSBridge::runOnExecutorQueue(std::function<void(JSIExecutor*)>&& task) noexcept {
  jsQueue_->runOnQueue([this, task = std::move(task)] { task(this->jsiExecutor_.get()); });
}

void NativeToJSBridge::loadBundle(const std::string&& buffer, const std::string&& sourceUrl) {
  runOnExecutorQueue([this, buffer = std::move(buffer), sourceUrl = std::move(sourceUrl)](JSIExecutor* executor) {
    executor->loadBundle(std::make_unique<facebook::jsi::StringBuffer>(buffer), sourceUrl);
  });
}

void NativeToJSBridge::invokeCallback(unsigned int callbackId) {
  runOnExecutorQueue([this, callbackId](JSIExecutor* executor) { executor->invokeCallback(callbackId); });
}
}  // namespace bridge